package com.github.bryx.workflow.command.executor;

import com.github.bryx.workflow.command.BaseCommand;
import com.github.bryx.workflow.command.CommandConfiguration;
import com.github.bryx.workflow.config.WorkflowInstanceAwareRegistry;
import com.github.bryx.workflow.handler.WorkflowInstanceAware;
import com.github.bryx.workflow.service.WorkflowRuntimeService;
import com.github.bryx.workflow.util.SpringUtil;
import com.github.bryx.workflow.util.StringUtil;
import lombok.Data;
import org.apache.commons.lang3.Validate;

/**
 * @Author jameswu
 * @Date 2021/6/10
 **/
@Data
public abstract class CommandExecutor<RETURN> {

    private BaseCommand command;

    private CommandExecutorHelper commandExecutorHelper;

    private WorkflowInstanceAware workflowInstanceAware;

    private String processDefKey;

    public static <RETURN> RETURN execute(BaseCommand command){
        CommandConfiguration commandConfiguration = command.getClass().getAnnotation(CommandConfiguration.class);
        Class<? extends CommandExecutor> executorClass = commandConfiguration.executor();
        CommandExecutor<RETURN> executor = SpringUtil.getApplicationContext().getBean(executorClass);
        executor.setCommand(command);
        executor.setCommandExecutorHelper(SpringUtil.getApplicationContext().getBean(CommandExecutorHelper.class));
        if (StringUtil.isNotEmpty(command.getProcessDefKey())){
            executor.setProcessDefKey(command.getProcessDefKey());
            executor.setWorkflowInstanceAware(retrieveWorkflowInstanceAware(command.getProcessDefKey()));
        }else{
            WorkflowRuntimeService workflowRuntimeService = SpringUtil.getApplicationContext().getBean(WorkflowRuntimeService.class);
            executor.setProcessDefKey(workflowRuntimeService.query().getProcessDefKeyOfWorkflowInstance(command.getWorkflowInstanceId()));
            executor.setWorkflowInstanceAware(retrieveWorkflowInstanceAware(executor.getProcessDefKey()));
        }
        // 前置
        executor.getWorkflowInstanceAware().preCommandExecute(executor.getProcessDefKey(), command);
        return executor.run();
    }

    public abstract RETURN run();

    private static WorkflowInstanceAware retrieveWorkflowInstanceAware(String workflowDefKey){
        WorkflowInstanceAwareRegistry workflowInstanceAwareRegistry = SpringUtil.getApplicationContext().getBean(WorkflowInstanceAwareRegistry.class);
        WorkflowInstanceAware aware = workflowInstanceAwareRegistry.getWorkflowInstanceAware(workflowDefKey);
        Validate.notNull(aware, "please register workflow instance aware with process def key %s", workflowDefKey);
        return aware;
    }
}
